home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / OpenTransport / FWOTDriver / EntryPoints.c < prev    next >
Encoding:
Text File  |  1999-05-17  |  39.5 KB  |  1,411 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        EntryPoints.c
  3.  
  4.     Contains:    This file contains the structures necessary for the STREAMS environment
  5.                 and also the routines that are not hardware dependent.
  6.  
  7.     Written by:    
  8.  
  9.     Copyright:    © 1994, 1996-1997 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.       <FW12>     3/18/97    ES        Changed protocol driver description version to final.
  14.       <FW11>     2/20/97    ES        Changed FWClientAsynchRequestParams buffer field to
  15.                                     receiveBuffer.
  16.       <FW10>      1/9/97    ES        Took out some debugging stuff. Removed fixed address allocation.
  17.        <FW9>    12/27/96    ES        Changed to connect and disconnect target units one at a time.
  18.        <FW8>    12/27/96    ES        Changed a bunch of "FWDriver"s to "FWClient"s. Changed to
  19.                                     protocol driver.
  20.        <FW7>    12/16/96    ES        Changed to work with new read/write/lock request/complete
  21.                                     processing mechanism.
  22.        <FW6>     9/16/96    ES        Changed FireWire driver interface procs to return command
  23.                                     acceptance.
  24.        <FW5>     8/29/96    ES        Changed FWRegisterDriver to take driver interface proc table.
  25.        <FW4>     8/16/96    ES        Changed FWDriverInterface to call FWDriverCommandIsComplete.
  26.        <FW3>      8/1/96    ES        Took out unused local variables.
  27.        <FW2>     4/15/96    ES        Update for use with Driver Notification services.
  28.        <FW1>     3/27/96    ES        first checked in
  29.  
  30.     To Do:
  31. */
  32.  
  33.  
  34. //-----------------------------------------------------------------------------------------
  35. // Header files
  36. //-----------------------------------------------------------------------------------------
  37.  
  38. #include <OpenTptModule.h>            // Open Transport files
  39. #include <OpenTptPCISupport.h>        
  40. #include <OpenTptDevLinks.h>
  41. #include <OpenTptLinks.h>
  42. #include <miioccom.h>
  43. #include <stropts.h>
  44. #include <dlpi.h>
  45.  
  46. #include <Kernel.h>                    // System files
  47. #include <DriverServices.h>
  48. #include <Devices.h>
  49. #include <CodeFragments.h>
  50. #include <Interrupts.h>
  51. #include <FireWire.h>
  52.  
  53. #include "EntryPoints.h"            // our files
  54. #include "DLPIRoutines.h"            
  55. #include "HWSpecific.h"
  56. /*zzz*/
  57. static char  debugStr[256];
  58. /*zzz*/
  59.  
  60. //-----------------------------------------------------------------------------------------
  61. // STREAMS Structures
  62. //-----------------------------------------------------------------------------------------
  63.  
  64. static struct module_info moduleInformation = 
  65.     {
  66.     kEnetModuleID,                    // indicates this dlpi is ethernet 
  67.     kModuleDeviceInfoName,
  68.     0,                                // minimum packet data size
  69.     kMaxTransmitSize,                // maximum packet data size 
  70.     6000,                            // hi water mark
  71.     5000                            // low water mark 
  72.     };
  73.  
  74. static struct qinit    readSide = 
  75.     {
  76.     putq,
  77.     NULL,
  78.     OpenServiceRoutine,
  79.     CloseServiceRoutine,
  80.     NULL,                            // reserved for future use
  81.     &moduleInformation,
  82.     NULL                            // no module_stat structure
  83.     };
  84.  
  85.  
  86. static struct qinit    writeSide = 
  87.     {
  88.     WritePutRoutine,
  89.     WriteServiceRoutine,
  90.     NULL,                            // no module open needed for write side
  91.     NULL,                            // no module close needed for write side
  92.     NULL,                            // reserved for future use
  93.     &moduleInformation,
  94.     NULL                            // no module_stat structure
  95.     };
  96.  
  97.  
  98. static struct streamtab streamTabInformation = 
  99.     {
  100.     &readSide,
  101.     &writeSide,
  102.     NULL,                            // lower read/write qinit (multiplexors only)
  103.     NULL
  104.     };
  105.  
  106. static struct install_info theInstallInformation =
  107.     {
  108.     &streamTabInformation,             
  109.     kOTModIsDriver,                         // install flags 
  110.     SQLVL_MODULE,                            // Synchronization level 
  111.     0,                                        // Shared writer list buddy 
  112.     0                                        // Flag - set to 0 
  113.     };
  114.  
  115. //-----------------------------------------------------------------------------------------
  116. // Global variable for the entire CFM
  117. //-----------------------------------------------------------------------------------------
  118.  
  119. DLPIPrivateData *gDLPIPrivateData = NULL;    // private data for our dlpi driver     
  120.  
  121. //-----------------------------------------------------------------------------------------
  122. //    Description:
  123. //        This data stucture entry point is exported through the cfm mechanism.  Information
  124. //        about the hardware that this driver works with is located in this structure.
  125. //
  126. //-----------------------------------------------------------------------------------------
  127.  
  128. enum
  129. {
  130.     kFrameFlags = kOTFramingEthernet | kOTFramingEthernetIPX | kOTFraming8022
  131. };
  132.  
  133. DriverDescription TheDriverDescription =
  134. {
  135. // Signature Info
  136.     kTheDescriptionSignature,                    // signature always first
  137.     kInitialDriverDescriptor,                    // version second
  138.  
  139. // Type Info
  140.     "\pFWOpenTransport",                        // Our name, module info name must match
  141.     1,0,finalStage,0,                            // Major, Minor, Stage, Rev
  142.  
  143. // OS Runtime Info
  144.     kDriverIsUnderExpertControl,                // Runtime Options
  145.     "\penet",                                    // should be kEnetName
  146.     0,0,0,0,0,0,0,0,                            // reserve 8 longs
  147.  
  148. // OS Service Info
  149.     1,                                            // Number of Service Categories                            
  150.     kServiceCategoryOpenTransport,                // We support the 'otan' category
  151.     OTPCIServiceType(kOTEthernetDevice,kFrameFlags,0,1),
  152.     1,0,0,0                                        // Major, Minor, Stage, Rev
  153. };
  154.  
  155. FWPDriverDescription ThePDriverDescription =
  156. {
  157.     kTheFWPDriverDescriptionSignature,
  158.     kInitialFWPDriverDescriptor,
  159.  
  160.     kServiceCategoryFWDriver,
  161.     0,0,finalStage,0,
  162.  
  163.     0,
  164.     "\pFWOpenTransport"
  165. };
  166.  
  167.  
  168. ////////////////////////////////////////////////////////////////////////////////
  169. //
  170. // FWClientWriteCompleteInterface
  171. //
  172. //   FireWire client interface for handling completed write requests.
  173. //
  174.  
  175. OSStatus    FWClientWriteCompleteInterface(
  176.     FWClientAsynchRequestParamsPtr
  177.                                 pFWClientAsynchRequestParams,
  178.     UInt32                        *pCommandAcceptance)
  179. {
  180.     DLPIPrivateData                *pDLPIPrivateData;
  181.     mblk_t                        *thePacket;
  182.     UInt32                        dataSize;
  183.     OSStatus                    status = noErr;
  184.  
  185.     // Notify OpenTransport that we're processing in an interrupt.
  186.     OTEnterInterrupt ();
  187.  
  188.     // Get our private data.
  189.     pDLPIPrivateData = (DLPIPrivateData *)
  190.         pFWClientAsynchRequestParams->pAddressSpecificData;
  191.  
  192.     // Pass on received packet in a message block.
  193.     dataSize = pFWClientAsynchRequestParams->length;
  194.     if ((thePacket = allocb (dataSize, BPRI_HI)) != NULL)
  195.     {
  196.         // Write received data into message block.
  197.         bcopy (pFWClientAsynchRequestParams->receiveBuffer,
  198.                thePacket->b_rptr,
  199.                dataSize);
  200.         thePacket->b_wptr += dataSize;
  201.  
  202.         // Put message block on queue, so callback routine can
  203.         // dequeue it and pass it on to upper layers.
  204.         EnqueueElement (&(pDLPIPrivateData->RxPacketQueue),
  205.                         (QElem *) thePacket,
  206.                         kNoInterrupts);
  207.         OTScheduleDeferredTask (pDLPIPrivateData->RxDeferredTaskCookie);
  208.     }
  209.  
  210.     // Complete FireWire client command.
  211.     FWClientCommandIsComplete
  212.         (pFWClientAsynchRequestParams->fwClientInterfaceParams.fwClientCommandID,
  213.          status);
  214.  
  215.     // Return command acceptance.
  216.     //zzz is this the right way?  If we've completed the command, we can accept more.
  217.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  218.  
  219.     // Notify OpenTransport that we're done processing in an
  220.     // interrupt.
  221.     OTLeaveInterrupt ();
  222.  
  223.     return (status);
  224. }
  225.  
  226.  
  227. ////////////////////////////////////////////////////////////////////////////////
  228. //
  229. // FWPDriverUnitAdded
  230. //
  231. //   FireWire protocol driver interface for handling added units.
  232. //
  233.  
  234. OSStatus    FWPDriverUnitAdded(
  235.     FWPDriverID                    fwPDriverID,
  236.     UInt32                        fwPDriverSpecificData,
  237.     FWUnitID                    fwUnitID)
  238. {
  239.     CSRROMEntryIterator            csrROMIterator = kInvalidCSRROMIterator;
  240.     CSRROMSearchCriteria        searchCriteria;
  241.     CSRROMEntryID                unitCSRROMEntryID,
  242.                                 unitInfoCSRROMEntryID = kInvalidCSRROMEntryID;
  243.     UInt32                        unitInfoSize;
  244.     Boolean                        unitAdded;
  245.     Boolean                        done;
  246.     OSStatus                    status = noErr;
  247.  
  248.     // Set target unit.
  249.     if (!gDLPIPrivateData->unitConnection)
  250.     {
  251.         gDLPIPrivateData->fwUnitID = fwUnitID;
  252.         status = FWAddUnitConnection (fwUnitID, fwPDriverID);
  253.         if (status == noErr)
  254.         {
  255.             gDLPIPrivateData->unitConnection = true;
  256.             unitAdded = true;
  257.         }
  258.     }
  259.     else
  260.     {
  261.         unitAdded = false;
  262.     }
  263.  
  264.     // Get node's unit dependent information.
  265.     if ((status == noErr) && (unitAdded))
  266.     {
  267.         // Get unit CSR ROM entry ID.
  268.         status = FWGetUnitCSRROMEntryID ((FWReferenceID) gDLPIPrivateData->fwUnitID,
  269.                                          &unitCSRROMEntryID);
  270.  
  271.         // Create a CSR ROM search iterator.
  272.         if (status == noErr)
  273.         {
  274.             status = FWCSRROMCreateIterator (&csrROMIterator,
  275.                                              (FWReferenceID) gDLPIPrivateData->fwUnitID);
  276.         }
  277.  
  278.         // Set iterator to start searching at our unit directory.
  279.         if (status == noErr)
  280.         {
  281.             status = FWCSRROMSetIterator (csrROMIterator,
  282.                                           unitCSRROMEntryID,
  283.                                           kIterateDescendants);
  284.         }
  285.  
  286.         // Search for unit dependent info leaf.
  287.         if (status == noErr)
  288.         {
  289.             searchCriteria.csrROMSearchType = kCSRROMSearchForKey;
  290.             searchCriteria.keyType = kCSRLeafKeyTypeBit;
  291.             searchCriteria.keyHi = 0;
  292.             searchCriteria.keyLo = 1 << kCSRUnitDependentInfoKey;
  293.             unitInfoSize = sizeof (FWAddress);
  294.             status = FWCSRROMEntrySearch (csrROMIterator,
  295.                                           kIterateContinue,
  296.                                           &unitInfoCSRROMEntryID,
  297.                                           &done,
  298.                                           &searchCriteria,
  299.                                           (Ptr) &(gDLPIPrivateData->targetAddress),
  300.                                           &unitInfoSize);
  301.         }
  302.  
  303.         // Clean up.
  304.         if (csrROMIterator != kInvalidCSRROMIterator)
  305.             FWCSRROMDisposeIterator (csrROMIterator);
  306.         if (unitInfoCSRROMEntryID != kInvalidCSRROMEntryID)
  307.             FWCSRROMDisposeEntryID (unitInfoCSRROMEntryID);
  308.     }
  309.  
  310.     // Set up some resources for target.
  311.     if ((status == noErr) && (unitAdded))
  312.     {
  313.         FWAllocateAsynchCommandObject (&(gDLPIPrivateData->asynchCommandObjectID));
  314.         FWSetFWCommandParams (gDLPIPrivateData->asynchCommandObjectID,
  315.                               (FWReferenceID) gDLPIPrivateData->fwUnitID,
  316.                               0,
  317.                               ABCVendorTransmitCompletion,
  318.                               0);
  319.         FWSetAsynchCommandMaxRetries (gDLPIPrivateData->asynchCommandObjectID, 8);
  320.  
  321.         FWSetMaxPayloadSize ((FWReferenceID) gDLPIPrivateData->fwUnitID, kMaxTransmitSize);
  322.     }
  323.  
  324.     return (status);
  325. }
  326.  
  327.  
  328. ////////////////////////////////////////////////////////////////////////////////
  329. //
  330. // FWPDriverUnitRemoved
  331. //
  332. //   FireWire protocol driver interface for handling removed units.
  333. //
  334.  
  335. OSStatus    FWPDriverUnitRemoved(
  336.     FWPDriverID                    fwPDriverID,
  337.     UInt32                        fwPDriverSpecificData,
  338.     FWUnitID                    fwUnitID)
  339. {
  340.     OSStatus                    status = noErr;
  341.  
  342.     // Clear target unit.
  343.     if ((gDLPIPrivateData->unitConnection) && (gDLPIPrivateData->fwUnitID == fwUnitID))
  344.     {
  345.         FWDeallocateFWCommandObject (gDLPIPrivateData->asynchCommandObjectID);
  346.         FWRemoveUnitConnection (gDLPIPrivateData->fwUnitID, fwPDriverID);
  347.         gDLPIPrivateData->unitConnection = false;
  348.         gDLPIPrivateData->fwUnitID = kInvalidFWUnitID;
  349.     }
  350.  
  351.     return (status);
  352. }
  353.  
  354.  
  355. //-----------------------------------------------------------------------------------------
  356. //    Description:
  357. //        This routine is used by the driver to validate that our hardware is available.
  358. //        By using the ID we can find out the logical address of the card space (memory or
  359. //        I/O).
  360. //
  361. //        Next we should check if this driver can work with that card.  If the driver can 
  362. //        use the card then return kOTNoError.  The logical address can be used with
  363. //        C pointers (even for I/O space) since GetPCICardBaseAddress returned a logical
  364. //        address.
  365. //
  366. //        Keep in mind that even if the dlpi responds with kOTNoError the user may decide
  367. //        to not use your card...so the card state should be in the same state as when
  368. //        the routine was called.  In other words, turn off the card before you leave
  369. //        this routine and also deallocate any memory that you allocating.  The dlpi
  370. //        may be unloaded from memory so do not expect to have globals between the
  371. //        the ValidateHardware routine and InitStreamModule.
  372. //    
  373. //    Input:
  374. //        theID - node id of the card in the system registry
  375. //
  376. //    Output:
  377. //        kOTNoError if the hardware is available
  378. //        kENXIOErr, if could not obtain card base address or driver does not work with card
  379. //
  380. //-----------------------------------------------------------------------------------------
  381. OTResult ValidateHardware(RegEntryID *theID)
  382. {
  383. OTResult    error = kENXIOErr;        // default error code
  384.     
  385.  
  386. error = 0;
  387.  
  388. return error;
  389. }
  390.  
  391. //-----------------------------------------------------------------------------------------
  392. //    Description:
  393. //        This routine is required and will only be called once.  The routine must
  394. //        call OTInitModule().  At this point Open Transport has made the decision to
  395. //        use our card for a network connection.  We must save the RegEntryID in case
  396. //        we need it later.  We should get the card assigned address and save
  397. //        it in the dlpi private data area.  The hw must be initialized and memory
  398. //        allocated for dma buffers, install isrs, ....
  399. //
  400. //        Open Transport will start calling our open, put, and service routines after
  401. //        this routine if we return true.
  402. //    
  403. //    Input:
  404. //        theID - node id of the card in the system registry
  405. //
  406. //    Output:
  407. //        true, if initialization was successful
  408. //        false, if initialization failed
  409. //
  410. //-----------------------------------------------------------------------------------------
  411. Boolean    InitStreamModule(RegEntryID *theID)
  412. {
  413. Boolean    initOK;
  414.  
  415.  
  416. initOK = OTInitModule();
  417. if (initOK)
  418.     {
  419.     ABCVendorInitialize(theID);            // gDLPIPrivateData is set in this routine
  420.     
  421.     if (gDLPIPrivateData == NULL)        // was initialization successful?
  422.         {
  423.         initOK = false;                 // indicate we failed
  424.         OTTerminateModule();            // disconnect ourselves from Open Transport
  425.         }
  426.     }
  427.     
  428. return initOK;
  429. }
  430.  
  431. //-----------------------------------------------------------------------------------------
  432. //    Description:
  433. //        This routine is required and will only be called when the driver is about to be 
  434. //        unloaded.   At this point the driver is going away so we should close down
  435. //        the hardware.  If we get reopened then the InitStreamModule() will get called 
  436. //        again.  The routine must call OTTerminateModule().  
  437. //    
  438. //    Input:
  439. //        NONE
  440. //
  441. //    Output:
  442. //        NONE
  443. //
  444. //-----------------------------------------------------------------------------------------
  445. void TerminateStreamModule(void)
  446. {
  447.  
  448. if (gDLPIPrivateData)
  449.     {
  450.     ABCVendorClose();
  451.     gDLPIPrivateData = NULL;
  452.     }
  453.  
  454. OTTerminateModule();
  455. }
  456.  
  457. //-----------------------------------------------------------------------------------------
  458. //    Description:
  459. //        This is the cfm initialization routine.  It is not required and is almost a 
  460. //        duplication of the InitStreamModule() routine.
  461. //
  462. //    Input:
  463. //        theInitBlock - block containing various cfm information
  464. //
  465. //    Output:
  466. //        NONE
  467. //
  468. //-----------------------------------------------------------------------------------------
  469. OSErr InitCFMRoutine(CFragInitBlock *theInitBlock)
  470. {
  471.  
  472. return kOTNoError;
  473. }
  474.  
  475. //-----------------------------------------------------------------------------------------
  476. //    Description:
  477. //        This is the cfm termination routine.  It is not required and is almost a 
  478. //        duplication of the TerminateStreamModule() routine.
  479. //
  480. //    Input:
  481. //        NONE
  482. //
  483. //    Output:
  484. //        NONE
  485. //
  486. //-----------------------------------------------------------------------------------------
  487. void TerminateCFMRoutine(void)
  488. {
  489.  
  490. }
  491.  
  492. //-----------------------------------------------------------------------------------------
  493. //    Description:
  494. //        This routine returns a pointer to the install_info structure.  The
  495. //        name of the routine must be "GetOTInstallInfo" because OT loads the
  496. //        the function pointer by name.
  497. //
  498. //    Input:
  499. //        NONE
  500. //
  501. //    Output:
  502. //        returns the install_info pointer
  503. //
  504. //-----------------------------------------------------------------------------------------
  505. install_info* GetOTInstallInfo(void)
  506. {
  507.  
  508. return &theInstallInformation;
  509. }
  510.  
  511. //-----------------------------------------------------------------------------------------
  512. //    Description:
  513. //        This routine is called each time a new stream is created.  The
  514. //        stream structure is allocated and then filled in accordingly.  The
  515. //        address of the stream is stored in the dlpi private data and in the read
  516. //        queue data slot.
  517. //
  518. //    Input:
  519. //        q - write queue
  520. //        devp - device number that consists of major and minor
  521. //        genericFlag - not currently used
  522. //        sflag - indicates special open options
  523. //        crp - not currently used
  524. //
  525. //    Output:
  526. //        kOTNoError, if no problem occurred
  527. //        error, if no memory or the client tried to open as a module instead of dlpi
  528. //
  529. //-----------------------------------------------------------------------------------------
  530. int OpenServiceRoutine(queue_t *q, dev_t *devp, int genericflag, int sflag, cred_t *crp)
  531. {
  532. DLPIStream             *theStream;
  533. minor_t             minor_number;
  534.  
  535. if (sflag == MODOPEN)    // this is a dlpi not a module
  536.     return(EINVAL);
  537.  
  538. if (q->q_ptr != NULL)    // this must be a reopen, a stream is already attached
  539.     return kOTNoError;
  540.     
  541.  
  542. if (sflag == CLONEOPEN)     // new streams are opened using the clone
  543.     {        
  544.         
  545.     if ((theStream = OTAllocMem(sizeof(DLPIStream))) == NULL)    // get memory for stream struct        
  546.         return(ENOMEM);
  547.  
  548.     bzero(theStream,sizeof( DLPIStream ));        // set everything to zero
  549.         
  550.     theStream->bufferTimerMsg = mi_timer_alloc(WR(q),sizeof(UInt32));
  551.     if (theStream->bufferTimerMsg == NULL)
  552.         {
  553.         OTFreeMem(theStream);
  554.         return(ENOMEM);
  555.         }    
  556.  
  557.     minor_number = GenerateUniqueMinorDevice();
  558.     *devp = makedevice(getemajor(*devp), minor_number);
  559.  
  560.         // initialize the stream structure
  561.     theStream->readQueue = q;
  562.     theStream->idType = NULL;
  563.     theStream->dlpiState = DL_UNBOUND;
  564.     theStream->streamFlags = NULL;
  565.     theStream->minorDevice = minor_number; 
  566.     
  567.     q->q_ptr = (char *)theStream;
  568.     WR(q)->q_ptr = (char *)theStream;
  569.     
  570.     *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = NULL;
  571.  
  572.     EnqueueElement(&gDLPIPrivateData->dlpiStreamsQueue,(QElem *)theStream,kBothTxRxInterrupts);
  573.     }
  574.     
  575. return kOTNoError;
  576. }
  577.  
  578. //-----------------------------------------------------------------------------------------
  579. //    Description:
  580. //        This routine closes a stream. All multicast addresses are unregistered and then
  581. //        the memory for the streams structure is deallocated.
  582. //
  583. //    Input:
  584. //        q - write queue
  585. //        dummy1 - not currently used
  586. //        dummy2 - not currently used
  587. //
  588. //    Output:
  589. //        always return kOTNoError
  590. //
  591. //-----------------------------------------------------------------------------------------
  592. int CloseServiceRoutine(queue_t *q, int dummy1, cred_t *dummy2)
  593. {
  594. DLPIStream        *theStream;
  595. mblk_t             *mp;
  596.  
  597. theStream = (DLPIStream *)q->q_ptr;
  598.  
  599. if (theStream->idType == kdlpiBufcallType)            // remove any buf call
  600.     unbufcall(theStream->timeoutID);
  601.  
  602. mi_timer_free(theStream->bufferTimerMsg);    // allocated in open stream for buffer time outs
  603.  
  604.     // disable all multicasts that this stream has registered 
  605. while ((mp = (mblk_t *)DequeueHead( &theStream->multicastQueue, kBothTxRxInterrupts)) != NULL)
  606.     {
  607.     ABCVendorUnregisterMulticast(mp->b_rptr);
  608.     freemsg(mp);
  609.     }
  610.     
  611. q->q_ptr = NULL;            // clear the stream pointers in the read & write queues
  612. (WR(q))->q_ptr = NULL;
  613.  
  614.     // remove this stream from our linked list of stream structures
  615. DequeueElement(&gDLPIPrivateData->dlpiStreamsQueue,(QElem *)theStream,kBothTxRxInterrupts);    
  616. OTFreeMem(theStream);        // and finally free the stream storage 
  617.  
  618. return kOTNoError;
  619. }
  620.  
  621. //-----------------------------------------------------------------------------------------
  622. //    Description:
  623. //        This routine is called when someone wants to put something on our write queue.
  624. //        Somethings are handled immediately are some are put on the write queue and
  625. //        then serviced during the write service routine.  If a message is received that
  626. //        the driver is not expecting then it is dropped on the floor.
  627. //
  628. //    Input:
  629. //        q - the write queue 
  630. //        mp - message that we need to process
  631. //
  632. //    Output:
  633. //        returns true
  634. //
  635. //-----------------------------------------------------------------------------------------
  636. int WritePutRoutine(queue_t *q, mblk_t *mp)
  637. {
  638. union DL_primitives     *dlp;
  639. UInt32                     prim;
  640. DLPIStream                 *theStream;
  641.  
  642. switch (mp->b_datap->db_type) 
  643.     {
  644.     case M_IOCTL:
  645.         IOCtlTheStream(q, mp);
  646.         break;
  647.     case M_FLUSH:
  648.         FlushTheStream(q, mp);
  649.         break;
  650.     case M_PCSIG:    // timer messages come here
  651.         HandleTimerMessages(q, mp);
  652.         break;
  653.     case M_PROTO:
  654.     case M_PCPROTO:
  655.         dlp = (union DL_primitives *)mp->b_rptr;
  656.         prim = dlp->dl_primitive;
  657.         if (prim == DL_UNITDATA_REQ)    // normal transmit packet
  658.             {
  659.             theStream = (DLPIStream *)q->q_ptr;
  660.             DoUnitData(theStream, mp);
  661.             }
  662.         else
  663.             putq(q, mp);        // everything else waits until the service routine
  664.         break;
  665.     case M_DATA:    // raw packet, just send it out with dlpi manipulation
  666.         PreparePacketToBeSent(mp); 
  667.         break;
  668.     case M_COPYIN:
  669.     case M_COPYOUT:
  670.     case M_ERROR:
  671.     case M_HANGUP:
  672.     case M_IOCACK:
  673.     case M_IOCNAK:
  674.     case M_HPDATA:
  675.     case M_STOP:
  676.     case M_START:
  677.     case M_STOPI:
  678.     case M_STARTI:
  679.     case M_READ:
  680.     case M_SETOPTS:
  681.     case M_SIG:
  682.     case M_BREAK:
  683.     case M_DELAY:
  684.     case M_CTL:
  685.     case M_PASSFP:
  686.     case M_RSE:
  687.     default:
  688.         freemsg(mp);
  689.         break;
  690.     }
  691.  
  692. return(kTrue);
  693. }
  694.  
  695. //-----------------------------------------------------------------------------------------
  696. //    Description:
  697. //        This routine handles everything that was deferred (put on the write queue) during
  698. //        the write put routine.  This routine is really just a big switch statement to the
  699. //        different routines that handle each message.  If a message is not supported
  700. //        then an error ack is sent to the client.
  701. //
  702. //    Input:
  703. //        q - the write queue
  704. //
  705. //    Output:
  706. //        returns kOTNoError
  707. //
  708. //-----------------------------------------------------------------------------------------
  709. int WriteServiceRoutine(queue_t *q)
  710. {
  711. mblk_t                     *mp;
  712. DLPIStream                 *theStream;
  713. UInt32                     err, prim;
  714. union DL_primitives     *dlp;
  715.  
  716. if ((theStream = (DLPIStream *)q->q_ptr) == NULL || (gDLPIPrivateData == NULL))
  717.     return kOTNoError;
  718.  
  719. while ((mp = getq(q)) != NULL)         // continue retrieving messages until empty
  720.     {
  721.     err = kOTNoError;
  722.     dlp = (union DL_primitives *)mp->b_rptr;
  723.     prim = dlp->dl_primitive;
  724.     switch (prim) 
  725.         {
  726.         case DL_XID_REQ:
  727.             if (DoXID(theStream, mp, 0) == kdlpiRETRY) 
  728.                 {
  729.                 putbq(q, mp);
  730.                 return kOTNoError;
  731.                 }
  732.             break;
  733.         case DL_XID_RES:
  734.             if (DoXID(theStream, mp, 1) == kdlpiRETRY) 
  735.                 {
  736.                 putbq(q, mp);
  737.                 return kOTNoError;
  738.                 }
  739.             break;
  740.         case DL_TEST_REQ:
  741.             if (SendTestPacket(theStream, mp, 0) == kdlpiRETRY) 
  742.                 {
  743.                 putbq(q, mp);
  744.                 return kOTNoError;
  745.                 }
  746.             break;
  747.         case DL_TEST_RES:
  748.             if (SendTestPacket(theStream, mp, 1) == kdlpiRETRY) 
  749.                 {
  750.                 putbq(q, mp);
  751.                 return kOTNoError;
  752.                 }
  753.             break;
  754.         case DL_INFO_REQ:
  755.             if (DoGeneralInfo(theStream) == kdlpiRETRY) 
  756.                 {
  757.                 putbq(q, mp);
  758.                 return kOTNoError;
  759.                 }
  760.             else            
  761.                 freemsg(mp);
  762.             break;
  763.         case DL_SET_PHYS_ADDR_REQ:
  764.             if (DoSetPhysicalAddress(theStream, mp) == kdlpiRETRY) 
  765.                 {
  766.                 putbq(q, mp);
  767.                 return kOTNoError;
  768.                 }
  769.             break;
  770.         case DL_BIND_REQ:
  771.             if (BindTheStream(theStream, mp) == kdlpiRETRY) 
  772.                 {
  773.                 putbq(q, mp);
  774.                 return kOTNoError;
  775.                 }
  776.             break;
  777.         case DL_UNBIND_REQ:
  778.             if (UnBindTheStream(theStream, mp) == kdlpiRETRY) 
  779.                     {
  780.                     putbq(q, mp);
  781.                     return kOTNoError;
  782.                     }
  783.             break;
  784.         case DL_SUBS_BIND_REQ:
  785.             if (SubsBindTheStream(theStream, mp) == kdlpiRETRY) 
  786.                 {
  787.                 putbq(q, mp);
  788.                 return kOTNoError;
  789.                 }
  790.             break;
  791.         case DL_SUBS_UNBIND_REQ:
  792.             if (UnSubsBindTheStream(theStream, mp) == kdlpiRETRY) 
  793.                     {
  794.                     putbq(q, mp);
  795.                     return kOTNoError;
  796.                     }
  797.             break;
  798.         case DL_ENABMULTI_REQ:
  799.             if (DoEnableMulticast(theStream, mp) == kdlpiRETRY) 
  800.                 {
  801.                 putbq(q, mp);
  802.                 return kOTNoError;
  803.                 }
  804.             break;
  805.         case DL_DISABMULTI_REQ:
  806.             if (DoDisableMulticast(theStream, mp) == kdlpiRETRY) 
  807.                 {
  808.                 putbq(q, mp);
  809.                 return kOTNoError;
  810.                 }
  811.             break;
  812.         case DL_PHYS_ADDR_REQ:
  813.             if (DoPhysicalAddressAck(theStream,mp) == kdlpiRETRY) 
  814.                 {
  815.                 putbq(q, mp);
  816.                 return kOTNoError;
  817.                 }
  818.             else
  819.                 freemsg(mp);
  820.             break;
  821. #if    0
  822.         case DL_GET_STATISTICS_REQ:
  823.             if (DoStatisticsAck(theStream,mp) == kdlpiRETRY) 
  824.                 {
  825.                 putbq(q, mp);
  826.                 return kOTNoError;
  827.                 }
  828.             else
  829.                 freemsg(mp);
  830.             break;
  831. #endif
  832.         case DL_ATTACH_REQ:
  833.         case DL_DETACH_REQ:
  834.         case DL_PROMISCON_REQ:
  835.         case DL_PROMISCOFF_REQ:
  836.         case DL_UDQOS_REQ:
  837.         case DL_CONNECT_REQ:
  838.         case DL_CONNECT_RES:
  839.         case DL_TOKEN_REQ:
  840.         case DL_DISCONNECT_REQ:
  841.         case DL_RESET_REQ:
  842.         case DL_RESET_RES:
  843.         case DL_DATA_ACK_REQ:
  844.         case DL_REPLY_REQ:
  845.         case DL_REPLY_UPDATE_REQ:
  846.             err = DL_NOTSUPPORTED; // fall through 
  847.         default:
  848.             if (err == kOTNoError)
  849.                 err = DL_BADPRIM;
  850.             if (DoErrorAck(theStream, mp, prim, err, 0) == kdlpiRETRY) 
  851.                 {
  852.                 putbq(q, mp);
  853.                 return kOTNoError;
  854.                 }
  855.             break;
  856.         }
  857.     }    // while 
  858.  
  859.  
  860. return kOTNoError;
  861. }
  862.  
  863. //-----------------------------------------------------------------------------------------
  864. //    Description:
  865. //        This routine handles all the ioctl calls made to the driver.  Currently only
  866. //        the mentat fast call is handled and the framing type.  
  867. //
  868. //        For the Mentat Fastpath...
  869. //            The dlpi is called and then returns a built header for the current stream.
  870. //
  871. //        For the framing type...
  872. //            If the kOTFraming8022 value is passed in then the general info routine
  873. //            should start returning DL_CSMACD.  If that value is not passed in then
  874. //            the general info routine should return DL_ETHER.
  875. //
  876. //    Input:
  877. //        q - the write queue
  878. //        mp - the message block that contains ioctl parameters
  879. //
  880. //    Output:
  881. //        NONE
  882. //
  883. //-----------------------------------------------------------------------------------------
  884. void IOCtlTheStream(queue_t *q, mblk_t *mp)
  885. {
  886. struct iocblk         *iocPtr = (struct iocblk *)mp->b_rptr;
  887. mblk_t                *headerMP;
  888. long                temp;
  889. DLPIStream             *theStream;
  890.  
  891. iocPtr->ioc_count = 0;
  892. iocPtr->ioc_error = 0;
  893. iocPtr->ioc_rval = 0;
  894.  
  895. switch( iocPtr->ioc_cmd )
  896.     {
  897.     case I_OTSetFramingType:        // toggles what the general info primitive returns
  898.         headerMP = mp->b_cont;    //  for dl_mac_type in dl_info_ack_t structure
  899.         mp->b_cont = NULL;
  900.         if ( headerMP == NULL || ((headerMP->b_wptr - headerMP->b_rptr) != sizeof(UInt32)) )
  901.             {
  902.             if (headerMP)
  903.                 freemsg(headerMP);
  904.             mp->b_datap->db_type = M_IOCNAK;
  905.             break;
  906.             }
  907.         temp = *(long*)headerMP->b_rptr;
  908.         if ( temp == kOTFraming8022 )
  909.             gDLPIPrivateData->privateFlags |= kpfFraming8022;
  910.         else
  911.             gDLPIPrivateData->privateFlags &= ~kpfFraming8022;
  912.         freemsg(headerMP);
  913.         mp->b_datap->db_type = M_IOCACK;
  914.         break;                                
  915.         
  916.     case DL_IOC_HDR_INFO:        // special Mentat call, for fast transmits
  917.         headerMP = mp->b_cont;    // get destination address information
  918.         mp->b_cont = NULL;        // disconnect dest addr mb
  919.  
  920.         headerMP = BuildTxPacketHeader((DLPIStream *)q->q_ptr, headerMP, kTrue);
  921.         
  922.         if (headerMP == NULL)    // could not allocate a message block large enough
  923.             {
  924.             iocPtr->ioc_error    = ENOMEM;
  925.             mp->b_datap->db_type = M_IOCNAK;
  926.             }
  927.         else
  928.             {
  929.             mp->b_cont = headerMP;        // hook mb's back together
  930.             mp->b_datap->db_type = M_IOCACK;
  931.             }
  932.  
  933.         break;                            
  934.         
  935.     case I_OTSetRawMode:            // toggles receive raw packet mode
  936.         theStream = (DLPIStream *)q->q_ptr;
  937.         headerMP = mp->b_cont;
  938.         if ((headerMP == NULL) || ((headerMP->b_wptr - headerMP->b_rptr) != sizeof(UInt32)) )
  939.             {
  940.             if (headerMP)
  941.                 freemsg(headerMP);
  942.             mp->b_datap->db_type = M_IOCNAK;
  943.             break;
  944.             }
  945.         temp = *(long*)headerMP->b_rptr;
  946.         if ( temp == kOTRawRcvOn )
  947.             {
  948.             theStream->streamFlags |= kReadRawPackets;
  949.             mp->b_datap->db_type = M_IOCACK;
  950.             }
  951.         else 
  952.             {
  953.             if ( temp == kOTRawRcvOff )
  954.                 {
  955.                 theStream->streamFlags &= ~kReadRawPackets;
  956.                 mp->b_datap->db_type = M_IOCACK;
  957.                 }
  958.             else    // message value is unkown to us
  959.                 mp->b_datap->db_type = M_IOCNAK;
  960.             }
  961.         break;                                
  962.         
  963.     default:
  964.         mp->b_datap->db_type = M_IOCNAK;
  965.         break;
  966.     }
  967.         
  968. qreply(q, mp);    // send response back up the stream
  969.  
  970. }
  971.  
  972. //-----------------------------------------------------------------------------------------
  973. //    Description:
  974. //        This routine receives the flush call and then it must send it up the read
  975. //        side of the stream.
  976. //
  977. //    Input:
  978. //        q - the write queue
  979. //        mp - the message block that contains the flush parameters
  980. //
  981. //    Output:
  982. //        NONE
  983. //
  984. //-----------------------------------------------------------------------------------------
  985. void FlushTheStream(queue_t *q, mblk_t *mp)
  986. {
  987. UInt8    *rptr = mp->b_rptr;
  988.  
  989. if (*rptr & FLUSHW) 
  990.     {
  991.     flushq(q, FLUSHALL);
  992.     *rptr &= ~FLUSHW;
  993.     }
  994.  
  995. if (*rptr & FLUSHR) 
  996.     {
  997.     flushq(RD(q), FLUSHALL);
  998.     qreply(q, mp);
  999.     }
  1000. else
  1001.     freemsg(mp);
  1002. }
  1003.  
  1004. //-----------------------------------------------------------------------------------------
  1005. //    Description:
  1006. //        This routine handles timer messages received on a stream.  The timer message
  1007. //        contains an identifier that we define.  Right now the routine only handles
  1008. //        one type of timer message.
  1009. //
  1010. //    Input:
  1011. //        writeQueue - write queue which has been given the timer message
  1012. //        mp - the message block that contains the flush parameters
  1013. //
  1014. //    Output:
  1015. //        NONE
  1016. //
  1017. //-----------------------------------------------------------------------------------------
  1018. void HandleTimerMessages(queue_t *writeQueue, mblk_t *mp)
  1019. {
  1020. DLPIStream             *theStream;
  1021. Boolean                isTimerValid;
  1022. UInt32                timerMsgType;
  1023.  
  1024. theStream = (DLPIStream *)writeQueue->q_ptr;
  1025.  
  1026. isTimerValid = mi_timer_valid(theStream->bufferTimerMsg);
  1027.  
  1028. if (isTimerValid == kFalse)
  1029.     return;
  1030.  
  1031. timerMsgType = *((UInt32 *)(theStream->bufferTimerMsg->b_rptr));
  1032.  
  1033. switch(timerMsgType)
  1034.     {
  1035.     case kEnableQueueTimerMsg:
  1036.         *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = NULL;
  1037.         qenable(writeQueue);
  1038.         break;
  1039.     default:
  1040.         break;
  1041.     }
  1042.  
  1043. }
  1044.  
  1045. //-----------------------------------------------------------------------------------------
  1046. //    Description:
  1047. //        This routine actually transmits the packet out on the wire.  If the packet
  1048. //        is an 802.3 packet then we must fill in the appropriate length (16 bits) in
  1049. //        the Ethernet header.  If for some reason the packet cannot be sent when this
  1050. //        routine is called then the packet must be kept around until the resources necessary
  1051. //        to send the packet are freed up.  One way of doing this might involve creating
  1052. //        a linked list of packets needing to be sent.  The resources will probably be
  1053. //        freed up during a transmit interrupt.  During the Tx ISR a deferred task is
  1054. //        setup to send any packets waiting on the linked list.  
  1055. //
  1056. //    Input:
  1057. //        thePacket - the message block containing the packet to send
  1058. //
  1059. //    Output:
  1060. //        NONE
  1061. //
  1062. //-----------------------------------------------------------------------------------------
  1063. void PreparePacketToBeSent(mblk_t *thePacket)
  1064. {
  1065. EnetPacketHeader     *enetHeader;
  1066. UInt16                len;
  1067.  
  1068. enetHeader = (EnetPacketHeader *)thePacket->b_rptr;
  1069.  
  1070. if (enetHeader->fProto == NULL) 
  1071.     {
  1072.     len = msgdsize(thePacket) - sizeof(EnetPacketHeader);
  1073.     enetHeader->fProto = len;
  1074.     }
  1075.  
  1076.     // Fill in the Ethernet source address.
  1077. OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,enetHeader->fSourceAddr); 
  1078.  
  1079. thePacket->b_next = NULL;
  1080.  
  1081. ABCVendorDisableInterrupts(kTxInterrupts);            
  1082.  
  1083. EnqueueElement(&gDLPIPrivateData->TxPacketQueue, (QElem *)thePacket,kNoInterrupts);        
  1084.  
  1085. AttemptPacketSend();    // may or may not be able to send the packet
  1086.  
  1087. ABCVendorEnableInterrupts(kTxInterrupts);            
  1088.  
  1089. }
  1090.  
  1091. //-----------------------------------------------------------------------------------------
  1092. //    Description:
  1093. //        This routine checks the tx packet queue to see if any packets are available 
  1094. //        for transmission.  If packets are found then the packet at the head is checked
  1095. //        to see if it can fit in the available dma resources. This routine is called by 
  1096. //        the normal thread of execution PreparePacketToBeSent and also by TxDTCallback.
  1097. //        Both times the tx interrupt enable will be turned off because we want to send
  1098. //        out as many packets as possible before we have to service the isr.  Otherwise 
  1099. //        we will pop back and forth between this routine and the tx isr which is not as 
  1100. //        efficient.
  1101. //
  1102. //    Input:
  1103. //        NONE
  1104. //
  1105. //    Output:
  1106. //        NONE
  1107. //
  1108. //-----------------------------------------------------------------------------------------
  1109. void AttemptPacketSend(void)
  1110. {
  1111.  
  1112. OSErr    error = kOTNoError;        
  1113. UInt16    packetSize;
  1114. mblk_t    *thePacket;
  1115.  
  1116. while ((error == kOTNoError) && gDLPIPrivateData->TxPacketQueue.qHead)
  1117.     {
  1118.     packetSize = msgdsize((mblk_t *)gDLPIPrivateData->TxPacketQueue.qHead);
  1119.     error = ABCVendorCheckTransmitterStatus(packetSize);        
  1120.     if (error == kOTNoError)        
  1121.         {
  1122.         thePacket = (mblk_t *)DequeueHead(&gDLPIPrivateData->TxPacketQueue,kNoInterrupts);
  1123.         ABCVendorTransmitOnePacket(thePacket,packetSize);    // this routine sends the packet    
  1124.         freemsg(thePacket);
  1125.         }
  1126.     }
  1127.  
  1128. }
  1129.  
  1130. //-----------------------------------------------------------------------------------------
  1131. //    Description:
  1132. //        This routine is called by the deferred task manager.  If for some reason a packet
  1133. //        could not be sent in the put routine and was deferred now would be a good time
  1134. //        to send it.
  1135. //
  1136. //    Input:
  1137. //        theParam - the refcon value for the call back, not used
  1138. //
  1139. //    Output:
  1140. //        NONE
  1141. //
  1142. //-----------------------------------------------------------------------------------------
  1143.  
  1144. pascal void TxDTCallback(void *theParam)
  1145. {
  1146.  
  1147.     // try to send any packets on the wait queue
  1148.  
  1149. ABCVendorDisableInterrupts(kTxInterrupts);            
  1150.  
  1151. AttemptPacketSend();    // may or may not be able to send the packet
  1152.  
  1153. ABCVendorEnableInterrupts(kTxInterrupts);            
  1154.  
  1155. }
  1156.  
  1157. //-----------------------------------------------------------------------------------------
  1158. //    Description:
  1159. //        This routine is called by the deferred task manager.  After the essential work
  1160. //        has been done in the ISR then this routine should do the bulk of the work.  
  1161. //
  1162. //        The isr placed the packet (in the form of a message block) on the rx packet 
  1163. //        queue.  It is the responsibility of this routine to dequeue all the packets
  1164. //        and pass them on to any clients (streams) that want them.
  1165. //
  1166. //    Input:
  1167. //        theParam - the refcon value for the call back return
  1168. //
  1169. //    Output:
  1170. //        NONE
  1171. //
  1172. //-----------------------------------------------------------------------------------------
  1173.  
  1174. pascal void RxDTCallback(void *theParam)
  1175. {
  1176. mblk_t    *thePacket;
  1177.  
  1178. while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->RxPacketQueue, kRxInterrupts))
  1179.     != NULL)
  1180.     FindStreamForReceivedPacket((DLPIStream *)gDLPIPrivateData->dlpiStreamsQueue.qHead, thePacket);    
  1181.  
  1182. }
  1183.  
  1184. //-----------------------------------------------------------------------------------------
  1185. //    Description:
  1186. //        This routine is used to enqueue an element onto the head of the list.  
  1187. //        An element is just a structure that has as it's first field a link.  The 
  1188. //        link field is used to connect structures in a linked list.  Each list contains
  1189. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1190. //
  1191. //    Input:
  1192. //        theQHdr - a system type queue header
  1193. //        whichIntsOff - the caller determines which interrupts need to be off
  1194. //
  1195. //    Output:
  1196. //        NONE
  1197. //
  1198. //-----------------------------------------------------------------------------------------
  1199. void EnqueueElementAtHead(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
  1200. {
  1201.  
  1202. ABCVendorDisableInterrupts(whichIntsOff);        
  1203.  
  1204. if ((theElem->qLink = theQHdr->qHead) != NULL)    // is the queue nonzero?
  1205.     theQHdr->qHead = theElem;
  1206. else    // empty list
  1207.     {    
  1208.     theQHdr->qTail = theElem;
  1209.     theElem->qLink = NULL;
  1210.     }
  1211.  
  1212. ABCVendorEnableInterrupts(whichIntsOff);        
  1213.  
  1214. }
  1215.  
  1216. //-----------------------------------------------------------------------------------------
  1217. //    Description:
  1218. //        This routine enqueues an element onto the back of the queue.
  1219. //        An element is just a structure that has as it's first field a link.  The 
  1220. //        link field is used to connect structures in a linked list.  Each list contains
  1221. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1222. //
  1223. //    Input:
  1224. //        theQHdr - a system type queue header
  1225. //        theElem - the element that should be placed on the queue
  1226. //        whichIntsOff - the caller determines which interrupts need to be off
  1227. //
  1228. //    Output:
  1229. //        NONE
  1230. //
  1231. //-----------------------------------------------------------------------------------------
  1232. void EnqueueElement(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
  1233. {
  1234.  
  1235. ABCVendorDisableInterrupts(whichIntsOff);        
  1236.  
  1237. if (theQHdr->qHead) 
  1238.     theQHdr->qTail->qLink = theElem;
  1239. else 
  1240.     theQHdr->qHead = theElem;
  1241.     
  1242. theQHdr->qTail = theElem;
  1243. theElem->qLink = NULL;
  1244.  
  1245. ABCVendorEnableInterrupts(whichIntsOff);        
  1246.  
  1247. }
  1248.  
  1249. //-----------------------------------------------------------------------------------------
  1250. //    Description:
  1251. //        This routine dequeues an element.  
  1252. //        An element is just a structure that has as it's first field a link.  The 
  1253. //        link field is used to connect structures in a linked list.  Each list contains
  1254. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1255. //
  1256. //    Input:
  1257. //        theQHdr - a system type queue header
  1258. //        theElem - the element that should be removed from the queue
  1259. //        whichIntsOff - the caller determines which interrupts need to be off
  1260. //
  1261. //    Output:
  1262. //        returns the element if it was found on the queue, NULL if the element was
  1263. //            not on the queue
  1264. //
  1265. //-----------------------------------------------------------------------------------------
  1266.  
  1267. QElem *DequeueElement(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
  1268. {
  1269. QElem    *listWalker,*previousElem;
  1270. Boolean    foundMatch = kFalse;
  1271.  
  1272. ABCVendorDisableInterrupts(whichIntsOff);        
  1273.  
  1274.     // no elements in the list or null element passed in        
  1275. if (((listWalker = theQHdr->qHead) == NULL) || (theElem == NULL))     
  1276.     {
  1277.     ABCVendorEnableInterrupts(whichIntsOff);        
  1278.     return NULL;
  1279.     }
  1280.  
  1281. if (theQHdr->qHead == theElem)            // only 1 element or/and element is the head
  1282.     {
  1283.     DequeueHead(theQHdr,whichIntsOff);        // interrupts will be enabled by enable     
  1284.     return theElem;                            //  routine in DequeueHead
  1285.     }
  1286.  
  1287.  
  1288. previousElem = listWalker;
  1289. while (listWalker && (!(listWalker == theElem)))    // walk thru list till we find a match    
  1290.     {
  1291.     previousElem = listWalker;
  1292.     listWalker = listWalker->qLink;
  1293.     }
  1294.  
  1295. if (listWalker)        // found the element in the list!    
  1296.     {
  1297.     previousElem->qLink = listWalker->qLink;    // disconnect element from the queue
  1298.     if (theElem == theQHdr->qTail)    // was the element the last element on the queue?
  1299.         theQHdr->qTail = previousElem;
  1300.         
  1301.     theElem->qLink = NULL;
  1302.     }
  1303. else
  1304.     theElem = NULL;        // element not in the list
  1305.     
  1306. ABCVendorEnableInterrupts(whichIntsOff);        
  1307.  
  1308. return theElem;
  1309. }
  1310.  
  1311. //-----------------------------------------------------------------------------------------
  1312. //    Description:
  1313. //        This routine dequeues the element at the head of the queue.
  1314. //        An element is just a structure that has as it's first field a link.  The 
  1315. //        link field is used to connect structures in a linked list.  Each list contains
  1316. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1317. //
  1318. //    Input:
  1319. //        theQHdr - a system type queue header
  1320. //        whichIntsOff - the caller determines which interrupts need to be off
  1321. //
  1322. //    Output:
  1323. //        returns the element that was at the head or NULL if the queue was empty
  1324. //
  1325. //-----------------------------------------------------------------------------------------
  1326.  
  1327. QElem *DequeueHead(QHdr *theQHdr, UInt16 whichIntsOff)
  1328. {
  1329. QElem    *theElem;
  1330.  
  1331. ABCVendorDisableInterrupts(whichIntsOff);        
  1332.         
  1333. if (theQHdr->qHead) 
  1334.     {
  1335.     if (theQHdr->qHead == theQHdr->qTail)        // only 1 element in the list
  1336.         theQHdr->qTail = NULL;
  1337.     theElem = theQHdr->qHead;
  1338.     theQHdr->qHead = theElem->qLink;
  1339.     theElem->qLink = NULL;
  1340.     } 
  1341. else 
  1342.     theElem = NULL;
  1343.  
  1344. ABCVendorEnableInterrupts(whichIntsOff);        
  1345.  
  1346. return theElem;
  1347. }
  1348.  
  1349. //-----------------------------------------------------------------------------------------
  1350. //    Description:
  1351. //        This routine generates a unique number for the minor device.  The last used
  1352. //        minor device number is stored in the globals.  The value is incremented by
  1353. //        1 and then each stream is checked to make sure it is not in use.
  1354. //
  1355. //    Input:
  1356. //        NONE
  1357. //
  1358. //    Output:
  1359. //        returns new minor device number for this driver
  1360. //
  1361. //-----------------------------------------------------------------------------------------
  1362.  
  1363. UInt16 GenerateUniqueMinorDevice(void)
  1364. {
  1365. Boolean    found;
  1366.  
  1367.     // start unique number guessing at where we ended last time, we have a possible
  1368.     //  64,000 minor numbers, so if we hit ffff we just start at 0 and continue
  1369.  
  1370. do    {
  1371.     found = CheckThisMinorDevice(++gDLPIPrivateData->currentMinorDeviceNumber);
  1372.     } while(!found);
  1373.  
  1374. return gDLPIPrivateData->currentMinorDeviceNumber;
  1375.  
  1376. }
  1377.  
  1378. //-----------------------------------------------------------------------------------------
  1379. //    Description:
  1380. //        This routine checks a minor device number against all the streams.  If the
  1381. //        minor device number is in use then the routine returns false.
  1382. //
  1383. //    Input:
  1384. //        minorDeviceNumber - the routine checks this device number against device
  1385. //            numbers in existing streams that are attached to this device.
  1386. //
  1387. //    Output:
  1388. //        true, if minorDeviceNumber is not in use by another streams
  1389. //        false, if minorDeviceNumber is in use by another stream
  1390. //
  1391. //-----------------------------------------------------------------------------------------
  1392.  
  1393. Boolean CheckThisMinorDevice(UInt16 minorDeviceNumber)
  1394. {
  1395. mblk_t    *mbWalker;
  1396. Boolean    isUnique = kTrue;
  1397.  
  1398. mbWalker = (mblk_t *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
  1399.  
  1400. while (mbWalker && isUnique) 
  1401.     {
  1402.     if (((DLPIStream *)mbWalker)->minorDevice == minorDeviceNumber)
  1403.         isUnique = kFalse;
  1404.     else
  1405.         mbWalker = mbWalker->b_next;
  1406.     }
  1407.     
  1408. return isUnique;
  1409. }
  1410.  
  1411.